En este caso vamos a sacar los datos de un dataset de Kaggle sobre análisis de sentimiento en Twitter.
Este análisis está basado en el dataset de Kaggle Tweet Sentiment Extraction.
Vamos a hacer un análisis de sentimiento.
Primero cargamos librería y los datasets, kaggle ya nos proporciona los datos separados en train y test, podríamos unirlos y hacer esta división pero consideramos dejarla tal y como nos lo proporciona kaggle dado que en el dataset train disponemos de una variable adicional.
En el conjunto de train, se proporciona una palabra o frase extraída del tweet (selected_text) que encapsula el sentimiento proporcionado. En el cojunto de test, sólo encontramos text y no selected_text.
Las variables (columnas) de las que disponemos son:
* textID - unique ID for each piece of text
* text - the text of the tweet
* sentiment - the general sentiment of the tweet
* selected_text - [train only] the text that supports the tweet's sentiment
Cargamos las librerías necesarias:
library(cowplot)
library(tm)
library(tidyverse)
library(stringr)
# Para la distancia Jaccard
library(stringdist)
# Para el análisis de sentimiento
#install.packages('sentimentr')
library(sentimentr)
# other textmining stuff
library(wordcloud)Cargamos los datos.
## [1] "data.frame"
Los dataset son dataframes.
Vemos las dimensiones.
## [1] 27481 4
## [1] 3534 3
Teniendo en cuenta tanto train como test, tenemos más de 30k datos.
Realicemos un pequeño análisis de los datos.
## textID text selected_text sentiment
## Length:27481 Length:27481 Length:27481 Length:27481
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## textID text sentiment
## Length:3534 Length:3534 Length:3534
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
## 'data.frame': 27481 obs. of 4 variables:
## $ textID : chr "cb774db0d1" "549e992a42" "088c60f138" "9642c003ef" ...
## $ text : chr " I`d have responded, if I were going" " Sooo SAD I will miss you here in San Diego!!!" "my boss is bullying me..." " what interview! leave me alone" ...
## $ selected_text: chr "I`d have responded, if I were going" "Sooo SAD" "bullying me" "leave me alone" ...
## $ sentiment : chr "neutral" "negative" "negative" "negative" ...
## 'data.frame': 3534 obs. of 3 variables:
## $ textID : chr "f87dea47db" "96d74cb729" "eee518ae67" "01082688c6" ...
## $ text : chr "Last session of the day http://twitpic.com/67ezh" " Shanghai is also really exciting (precisely -- skyscrapers galore). Good tweeps in China: (SH) (BJ)." "Recession hit Veronique Branquinho, she has to quit her company, such a shame!" " happy bday!" ...
## $ sentiment: chr "neutral" "positive" "negative" "positive" ...
Dado que el dataset de train contiene más de 27k obs. y, además, contiene la variable adicional selected_text, consideramos oportuno realizar el análisis de sentimiento sobre este dataset.
Parece que no hay datos NA’s, pero comprobemos.
## [1] FALSE
## [1] FALSE
El sentimiento (sentiment) es nuestra variable objetivo, nuestra target, vamos a verlo en una tabla.
##
## negative neutral positive
## 7781 11118 8582
##
## negative neutral positive
## 1001 1430 1103
Parece predominar el sentimiento neutral, luego el positivo y por el último el negativo.
Visualmente, con las funciones del paquete base de R, hacemos un gráfico.
Podemos visualizar con otra librería, ggplot2, mucho mas potente, con una visualización más óptima.
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
pie <- ggplot(train, aes(x = factor(1), fill = factor(sentiment))) +
geom_bar(width = 1)
pie + coord_polar(theta = "y")Visualización con barras.
Efectivamente, vemos que predomina el sentimiento neutral y, posteriomente, el positivo.
Podríamos decir que el 40% de los tweets son neutral, el 31% positive y el 28% negative, aproximadamente.
Nuestros datasets ya están divididos en train/test, siendo ambos de clase dataframe. El análisis de sentimiento, objetivo de la presente tarea, va a ser realizado sobre los datos de train, como hemos mencionado anteriormente.
Pasamos sentiment a factor.
Selección del texto y evaluación de su longitud.
df$text <- as.character(df$text)
df$selected_text <- as.character(df$selected_text)
df$length <- str_length(df$text) # Introduce una nueva variable, lenght (longitud)
df$length_sel <- str_length(df$selected_text) # Introduce una nueva variable, lenght_sel (longitud de selected_text)Eliminamos las entradas vacías. Los tweets que no tengo longitud mayor a 0 (al menos un caracter escrito).
Exploramos la longitud del texto frente a la frencuencia. Recordad que el número de caracteres máximo permitidos en Twitter es 280.
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 3.00 39.00 64.00 68.35 97.00 159.00
Podríamos decir que los tweets con mayor frecuencia, sobre text, son los que se sitúan en un número de caracteres entre 40-50; es decir, la mediana se situaría entre 40-50. La media se sitúa en 68,35.
Exploramos la longitud del texto seleccionado, selected_text. La variable selected_text, recordemos, encapsula el sentimiento proporcionado.
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 8.00 22.00 36.72 55.00 158.00
Sobre selected_text la media se sitúa en 36,72. Y la mediana estaría situada entre 0-10.
Podríamos decir que las palabras requeridas para encapsular el sentimiento del texto no son muchas, es decir, son pocas las palabras requeridas para evaluar el sentimiento (positivo, negativo, neutral) del texto/tweet completo. Realicemos el ratio.
df$length_ratio <- df$length_sel / df$length # Introduce una nueva variable, lenght_ratio
summary(df$length_ratio)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.008929 0.148148 0.632456 0.583509 1.000000 1.000000
La media del ratio se sitúa en 0,583509. Y en cuanto a la moda, las palabras que encapsulan el mismo son, con mayor frecuencia, la que albergan todos los caracteres.
Búsqueda de la posición inicial y final de selected_text.
Definimos las funciones y variables necesarias.
fun_find_first <- function(text, subtext) {
foo <- stringr::str_locate(text, fixed(subtext))
return(foo[1])
}
fun_find_second <- function(text, subtext) {
foo <- stringr::str_locate(text, fixed(subtext))
return(foo[2])
}
n <- nrow(df)
as <- 1:n
bs <- 1:n
for (i in 1:n) {
# print(i)
text <- df$text[i]
subtext <- df$selected_text[i]
a <- fun_find_first(text, subtext)
b <- fun_find_second(text, subtext)
as[i] <- a
bs[i] <- b
}
# Introducimos las variables begin, end, begin_rel y end_rel (relativas)
df$begin <- as
df$end <- bs
df$begin_rel <- df$begin / df$length
df$end_rel <- df$end / df$lengthBegin indica en qué caracter comienza selected_text de text. End, en qué caracter finaliza selected_text de text. Begin_rel y end_rel es la diferencia o ratio entre la variables begin y end con lenght.
Visualizaciones.
Inicio relativo.
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.006803 0.021277 0.060606 0.234003 0.426229 1.000000
Selected_text comienza al inicio de text, en los primeros caracteres generalmente.
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0229 0.5938 1.0000 0.7955 1.0000 1.0000
Selected_text finaliza generalmente hacia el final de text, en los últimos caracteres.
En realidad, estos gráficos no nos aportan gran información, pero pueden ser de interés. Inicio y final de selected_text muy próximo a incio y final de text, en general.
El índice de Jaccard o coeficiente de Jaccard mide el grado de similitud entre dos conjuntos, sea cual sea el tipo de elementos.
Siempre toma valores entre 0 y 1, correspondiente este último a la igualdad total entre ambos conjuntos.
# Introduce una nueva variable, jac
df$jac <- stringdist::stringdist(df$text, df$selected_text, method='jaccard')
summary(df$jac)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0000 0.0000 0.2000 0.3173 0.6667 0.9714
Histograma.
La media se sitúa en 0,3173. Moda en cero (histograma). Los conjuntos no son similares.
Generamos un dataframe, table, llamado sentiment_train con el id por elemento, el conteo de palabras, la desviación típica y ave_sentiment. Sentiment_by usa un algoritmo que aproxima el sentimiento (polaridad) del texto agrupando variables.
Ave_sentiment es el promedio de puntuación de sentimiento/polaridad promedio de agrupación. Es decir, si es negativo, el sentimiento es negativo, si es positivo, indica sentimiento positivo (lo vamos a definir como score_sentiment).
Word_count es el recuento de palabras sumado por variable de agrupación.
Sobre text.
sentiment_train <- sentimentr::sentiment_by(get_sentences(df$text))
# Se introduce en df las variables word_count y sentiment_score
df$sentiment_score <- sentiment_train$ave_sentiment
df$word_count <- sentiment_train$word_count
head(sentiment_train,10)## element_id word_count sd ave_sentiment
## 1: 1 8 NA 0.0000000
## 2: 2 10 NA -0.4743416
## 3: 3 5 NA -0.3354102
## 4: 4 5 0.347011 -0.2677943
## 5: 5 14 NA 0.0000000
## 6: 6 15 NA 0.0000000
## 7: 7 14 NA 0.4944333
## 8: 8 2 NA 0.0000000
## 9: 9 3 NA 0.0000000
## 10: 10 10 0.248998 0.2832496
Sobre selected_text, realizamos lo mismo.
sentiment_train_sel <- sentimentr::sentiment_by(get_sentences(df$selected_text))
# Se introduce en df las variables word_count_sel y sentiment_score_sel
df$sentiment_score_sel <- sentiment_train_sel$ave_sentiment
df$word_count_sel <- sentiment_train_sel$word_count
head(sentiment_train_sel,10)## element_id word_count sd ave_sentiment
## 1: 1 8 NA 0.0000000
## 2: 2 2 NA -0.3535534
## 3: 3 2 NA -0.5303301
## 4: 4 3 NA -0.4907477
## 5: 5 2 NA 0.0000000
## 6: 6 15 NA 0.0000000
## 7: 7 1 NA 0.7500000
## 8: 8 2 NA 0.0000000
## 9: 9 3 NA 0.0000000
## 10: 10 5 0.3535534 0.2728432
Correlación entre el SCORE del sentimiento en selected_text y en el texto completo.
sent_cor = round(cor(df$sentiment_score, df$sentiment_score_sel),3)
plot(df$sentiment_score, df$sentiment_score_sel, col='#00000040', pch=16,
main=paste0('Sentimiento en selected text vs full text; cor=',sent_cor))
grid()La correlación es perfecta, igual a 1, entre sentiment_score y sentiment_score_sel.
Realicemos ahora un análisis por cada uno de los sentimientos (positivo, negativo y neutral). Definamos stats_train con 13 variables (medias principalmente, y una mediana).
stats_train <- dplyr::group_by(df, sentiment) %>% summarise(n=n(),
mean_words = mean(word_count),
mean_words_sel = mean(word_count_sel),
mean_length = mean(length),
mean_length_sel = mean(length_sel),
mean_ratio = mean(length_ratio),
median_ratio = median(length_ratio),
mean_begin_rel = mean(begin_rel),
mean_end_rel = mean(end_rel),
mean_jac = mean(jac),
mean_sentiment_score = mean(sentiment_score),
mean_sentiment_score_sel = mean(sentiment_score_sel)
)## `summarise()` ungrouping output (override with `.groups` argument)
## sentiment n mean_words mean_words_sel mean_length mean_length_sel
## 1 negative 7781 13.85015 4.042025 70.50932 19.97314
## 2 neutral 11117 12.71044 12.371863 65.23945 62.79329
## 3 positive 8582 13.49091 3.571545 70.43743 18.12713
## mean_ratio median_ratio mean_begin_rel mean_end_rel mean_jac
## 1 0.3393714 0.2058824 0.37120726 0.6902020 0.50425156
## 2 0.9634154 1.0000000 0.04857945 0.9874804 0.01922133
## 3 0.3127351 0.1781500 0.34979966 0.6421680 0.53398443
## mean_sentiment_score mean_sentiment_score_sel
## 1 -0.13112250 -0.33618161
## 2 0.04496499 0.04512524
## 3 0.24948367 0.44112874
Esta tabla es muy interesante, nos da una información muy relevante, bien contenida, bien resumida y muy ilustrativa de nuestro análisis hasta el momento. Un dato que nos parece de relevancia comentar es mean_ratio y median_ratio, en el sentimiento neutral es igual a 1 (mediana) y 0,96 (media); es decir, la longitud de selected_text/longitud de text es en la mayoría de las ocasiones igual a 1 para el setimiento neutral, se usa aquí todo el texto (en este sentimiento), y no pocas palabras de text para definirlo (hecho que sí ocurre para el sentimiento negativa y positivo con mean_ratio de 0,3).
Definimos ahora, separemos más bien por cada uno de los sentimientos.
df_train_neutral <- dplyr::filter(df, sentiment=='neutral')
df_train_positive <- dplyr::filter(df, sentiment=='positive')
df_train_negative <- dplyr::filter(df, sentiment=='negative')Visualización de las funciones de distribución acumulada de la longitud por sentimientos (ecdf, Empirical Cumulative Distribution Function).
En text.
plot(ecdf(df_train_negative$length), col='red', main='Training - Longitud de text por sentimiento', xlab='Length of Text')
plot(ecdf(df_train_positive$length), col='green', add=TRUE)
plot(ecdf(df_train_neutral$length), col='blue', add=TRUE)
grid()
legend('topleft', text.width=25, legend=c('Negative','Positive','Neutral'), col=c('red','green','blue'), pch=16)Los tres sentimiento siguen una distribución acumulada muy parecida.
En selected_text.
plot(ecdf(df_train_negative$length_sel), col='red', main='Training - Longitud de selected text por sentimiento', xlab='Length of Selected Text')
plot(ecdf(df_train_positive$length_sel), col='green', add=TRUE)
plot(ecdf(df_train_neutral$length_sel), col='blue', add=TRUE)
grid()
legend('topleft', text.width=25, legend=c('Negative','Positive','Neutral'), col=c('red','green','blue'), pch=16)Vemos aquí una diferencia en selected_text con respecto a text. Observamos que la distribución acumulada en los sentimiento positivo y negativo tiene mayor pendiente que en el caso del sentimiento neutral.
Visualicemos el ratio selected_text/text.
plot(ecdf(df_train_negative$length_ratio), col='red', main='Training - Ratio Longitud Selected/Text Completo', xlab='Ratio')
plot(ecdf(df_train_positive$length_ratio), col='green', add=TRUE)
plot(ecdf(df_train_neutral$length_ratio), col='blue', add=TRUE)
grid()
legend('topleft', text.width=0.2, legend=c('Negative','Positive','Neutral'), col=c('red','green','blue'), pch=16)Vemos que en el ratio correspondiente al sentimiento neutral, parece que la logitud acumulada tiene un recorrido muy distinto al del otro par de sentimientos. Anteriormente, había visto que para el sentimiento neutral, mean_ratio era de 0,96 y median_ratio igual a 1.
Histogramas por sentimientos.
En text.
hist(df_train_neutral$sentiment_score, 50, col='blue', main='Sentimiento Score - Sentimientot=Neutral')hist(df_train_positive$sentiment_score, 50, col='green', main='Sentimiento Score - Sentimiento=Positive')hist(df_train_negative$sentiment_score, 50, col='red', main='Sentimiento Score - Sentimiento=Negative')Como cabía esperar, y hemos apuntado anteriormente al indicar el significado de la variable sentiment_score (si se positivo, tendrá valor positivo, si es negativo, negativo y si es neutral se situara entorno al valor 0) la frecuencia en el sentimiento neutral se sitúa entorno al valor 0, la frecuencia en el sentimiento positivo en valores mayores que cero y la frecuencia en el sentimiento negativo, valores menores a 0.
hist(df_train_positive$sentiment_score_sel, 50, col='darkgreen', main='Sentimiento Score Selected Text - Sentimiento=Positive')hist(df_train_negative$sentiment_score_sel, 50, col='darkred', main='Sentimiento Score Selected Text - Sentimiento=Negative')En la visualización del histograma sobre selected_text del score por sentimiento, ocurre lo mismo que lo descrito sobre text; sin embargo, observamos picos de frecuencia más pronunciados.
SmoothScatters de la longitud por cada sentimiento, es un scatterplot pero suavizado, una nube de puntos más suavizada.
smoothScatter(df_train_negative$length, df_train_negative$length_sel, xlab='Longitud Text', ylab='Longitud Selected Text',
main='Training - Sentimiento Negative')smoothScatter(df_train_positive$length, df_train_positive$length_sel, xlab='Longitud Text', ylab='Longitud Selected Text',
main='Training - Sentimiento Positive')smoothScatter(df_train_neutral$length, df_train_neutral$length_sel, xlab='Longitud Text', ylab='Longitud Selected Text',
main='Training - Sentimiento Neutral')Estos scatterplots están en sintonía con lo mencionado anteriormente y lo observado en la tabla stats_train, para el sentimiento neutral, selected_text y text son de longitud practicamente coincidente.
Veamos gráficos de correlaciones.
sent_cor = round(cor(df_train_neutral$sentiment_score, df_train_neutral$sentiment_score_sel),3)
plot(df_train_neutral$sentiment_score, df_train_neutral$sentiment_score_sel, col='#0000ff40', pch=16,
main=paste0('NEUTRAL - Sentimiento selected text vs text completo; cor=',sent_cor))
grid()La correlación del score para neutral en text y selected_text es de 0,97; positiva y fuerte (lineal).
sent_cor = round(cor(df_train_positive$sentiment_score, df_train_positive$sentiment_score_sel),3)
plot(df_train_positive$sentiment_score, df_train_positive$sentiment_score_sel, col='#00990040', pch=16,
main=paste0('POSITIVE - Sentimiento selected text vs text completo; cor=',sent_cor))
grid()La correlación del score para positive en selected_text y text es de 0,527, positiva, muy concentrada entre 0 y 0,5; es decir, es una relación no muy fuerte ya que la nube de puntos tiene una tendencia elíptica o circular, la relación es más bien débil.
sent_cor = round(cor(df_train_negative$sentiment_score, df_train_negative$sentiment_score_sel),3)
plot(df_train_negative$sentiment_score, df_train_negative$sentiment_score_sel, col='#99000040', pch=16,
main=paste0('NEGATIVE - Sentimiento selected text vs text completo; cor=',sent_cor))
grid()La correlación del score para negative en selected_text y text es de 0,557, positiva, muy concentrada entre -0.5 y 0; es decir, es una relación no muy fuerte ya que la nube de puntos tiene una tendencia elíptica o circular, la relación es más bien débil.
Histogramas distancia Jaccard por cada sentimiento (negativo, positivo y neutral).
hist(df_train_negative$jac,100, main='NEGATIVE - Jaccard distance selected vs full text', col='red')hist(df_train_positive$jac,100, main='POSITIVE - Jaccard distance selected vs full text', col='green')hist(df_train_neutral$jac[df_train_neutral$jac>0],100, main='NEUTRAL - Jaccard distance selected vs full text - sin ceros', col='blue')Como hemos mencionado anteriormente, los conjuntos text y selected_text no son similares en cuanto a longitud de caracteres.
Sentimiento Negativo:
ETL y construcción del corpus.
my_corpus <- tm::VCorpus(tm::VectorSource(df_train_negative$text))
# tidy text
my_corpus <- tm::tm_map(my_corpus, tm::removePunctuation)
my_corpus <- tm::tm_map(my_corpus, tm::content_transformer(tolower))
my_corpus <- tm::tm_map(my_corpus, removeWords, stopwords("english"))
my_corpus <- tm::tm_map(my_corpus, stemDocument)
# plot wordcloud
wordcloud::wordcloud(my_corpus, max.words=250, random.order=FALSE, color=rainbow(100))Para el sentimiento negativo pero selecionando sólo selected_text.
my_corpus <- tm::VCorpus(tm::VectorSource(df_train_negative$selected_text))
# tidy text
my_corpus <- tm::tm_map(my_corpus, tm::removePunctuation)
my_corpus <- tm::tm_map(my_corpus, tm::content_transformer(tolower))
my_corpus <- tm::tm_map(my_corpus, removeWords, stopwords("english"))
my_corpus <- tm::tm_map(my_corpus, stemDocument)
# plot wordcloud
wordcloud::wordcloud(my_corpus, max.words=250, random.order=FALSE, color=rainbow(100))Palabras como miss, sad, hate, can’t, suck, bad, bore, dont, work, now, day son algunas de las que más se mencionan en este sentimiento negativo.
Sentimiento Positivo:
En Text.
my_corpus <- tm::VCorpus(tm::VectorSource(df_train_positive$text))
# tidy text
my_corpus <- tm::tm_map(my_corpus, tm::removePunctuation)
my_corpus <- tm::tm_map(my_corpus, tm::content_transformer(tolower))
my_corpus <- tm::tm_map(my_corpus, removeWords, stopwords("english"))
my_corpus <- tm::tm_map(my_corpus, stemDocument)
# plot wordcloud
wordcloud::wordcloud(my_corpus, max.words=250, random.order=FALSE, color=rainbow(100))En selected_text.
my_corpus <- tm::VCorpus(tm::VectorSource(df_train_positive$selected_text))
# tidy text
my_corpus <- tm::tm_map(my_corpus, tm::removePunctuation)
my_corpus <- tm::tm_map(my_corpus, tm::content_transformer(tolower))
my_corpus <- tm::tm_map(my_corpus, removeWords, stopwords("english"))
my_corpus <- tm::tm_map(my_corpus, stemDocument)
# plot wordcloud
wordcloud::wordcloud(my_corpus, max.words=250, random.order=FALSE, color=rainbow(100))Palabras como good, love, happi, thank, day, great, hope, like, lol, mother, nice, fun, awesome son algunas de las destacadas para el sentimiento positivo.
Sentimiento Neutral:
En text. No lo vamos a realizar sobre selected_text puesto que no se diferencian mucho, como hemos dicho en varias ocasiones anteriormente.
my_corpus <- tm::VCorpus(tm::VectorSource(df_train_neutral$text))
# tidy text
my_corpus <- tm::tm_map(my_corpus, tm::removePunctuation)
my_corpus <- tm::tm_map(my_corpus, tm::content_transformer(tolower))
my_corpus <- tm::tm_map(my_corpus, removeWords, stopwords("english"))
my_corpus <- tm::tm_map(my_corpus, stemDocument)
# plot wordcloud
wordcloud::wordcloud(my_corpus, max.words=250, random.order=FALSE, color=rainbow(100))Palabras como day, work, just, get, now, today, time son algunas de las que se encuentran en sentmiento neutral, lo cierto que podríamos decir que son palabras vacías sin contexto.
Terminamos ofreciendo la información de la sesión.
## R version 4.0.0 (2020-04-24)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 18362)
##
## Matrix products: default
##
## locale:
## [1] LC_COLLATE=Spanish_Spain.1252 LC_CTYPE=Spanish_Spain.1252
## [3] LC_MONETARY=Spanish_Spain.1252 LC_NUMERIC=C
## [5] LC_TIME=Spanish_Spain.1252
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] gridExtra_2.3 wordcloud_2.6 RColorBrewer_1.1-2 sentimentr_2.7.1
## [5] stringdist_0.9.5.5 forcats_0.5.0 stringr_1.4.0 dplyr_1.0.0
## [9] purrr_0.3.4 readr_1.3.1 tidyr_1.1.0 tibble_3.0.1
## [13] ggplot2_3.3.1 tidyverse_1.3.0 tm_0.7-7 NLP_0.2-0
## [17] cowplot_1.0.0
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.4.6 textshape_1.7.1 lubridate_1.7.8 lattice_0.20-41
## [5] assertthat_0.2.1 digest_0.6.25 slam_0.1-47 R6_2.4.1
## [9] cellranger_1.1.0 backports_1.1.7 reprex_0.3.0 evaluate_0.14
## [13] httr_1.4.1 pillar_1.4.4 rlang_0.4.6 readxl_1.3.1
## [17] rstudioapi_0.11 data.table_1.12.8 textclean_0.9.3 blob_1.2.1
## [21] rmarkdown_2.2 labeling_0.3 munsell_0.5.0 broom_0.5.6
## [25] compiler_4.0.0 modelr_0.1.8 xfun_0.14 pkgconfig_2.0.3
## [29] qdapRegex_0.7.2 htmltools_0.4.0 tidyselect_1.1.0 fansi_0.4.1
## [33] crayon_1.3.4 dbplyr_1.4.4 withr_2.2.0 SnowballC_0.7.0
## [37] grid_4.0.0 nlme_3.1-147 jsonlite_1.6.1 gtable_0.3.0
## [41] lifecycle_0.2.0 DBI_1.1.0 magrittr_1.5 scales_1.1.1
## [45] KernSmooth_2.23-16 cli_2.0.2 stringi_1.4.6 farver_2.0.3
## [49] fs_1.4.1 syuzhet_1.0.4 xml2_1.3.2 ellipsis_0.3.1
## [53] generics_0.0.2 vctrs_0.3.0 tools_4.0.0 glue_1.4.1
## [57] hms_0.5.3 parallel_4.0.0 yaml_2.2.1 colorspace_1.4-1
## [61] lexicon_1.2.1 rvest_0.3.5 knitr_1.28 haven_2.3.0
Referencias
Parte de este código ha sido recopilado de las lecciones del profesor Santiago Mota, Master in Big Data and & Data Science at Complutense University of Madrid. También, otra parte del mismo ha sido inspirado a través de código diverso de los notebooks de Kaggle puestos a disposición por parte de los usuarios inscritos, aquí.
Comentarios
El presente código ha sido ejecutado en el sistema operativo version Windows 10, 64 bits, escogiendo formato de codificación en RStudio UTF-8.
A work by María Luisa Duque
marialdu@umc.es